package com.zadtek.sharkRider.util.gmap;

import android.app.IntentService;
import android.content.Context;
import android.content.Intent;
import android.location.Address;
import android.location.Geocoder;
import android.os.Bundle;
import android.os.ResultReceiver;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.Log;

import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.StringRequest;
import com.android.volley.toolbox.Volley;

import org.json.JSONArray;
import org.json.JSONObject;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;


/**
 * 1、根据经纬度搜索所在地理位置
 * 2、根据文字搜索地理位置
 * 3、根据经纬度搜索附近地理位置
 *
 * https://developers.google.com/places/web-service/search?hl=zh-cn
 *
 * Created by e on 2017/8/16.
 */

public class AddressService extends IntentService {


    public static final String EXTRA_RECEIVER = "Receiver";
    public static final String EXTRA_LATITUDE = "Latitude";
    public static final String EXTRA_LONGITUDE = "Longitude";
    public static final String EXTRA_FAILURE = "failure";
    public static final String EXTRA_ADDRESS = "address";
    public static final int RESULT_FAILURE = 1;
    public static final int RESULT_SUCCESS = 2;

    public static final String EXTRA_TYPE = "fetch_type";
    public static final int TYPE_LOCATION = 0;
    public static final int TYPE_ADDRESS = 1;
    public static final int TYPE_NEARBY = 2;

    public static final String ERROR_GEO_INVALID = "经纬度错误";
    public static final String ERROR_GOOGLE_SERVICE_INVALID = "谷歌服务不可用";
    public static final String ERROR_DATA_INVALID = "位置信息异常";

    private static final String TAG = "AddressService";
    protected ResultReceiver mReceiver;


    public static void fromAddress(Context context, ResultReceiver receiver, String address) {
        Intent intent = new Intent(context, AddressService.class);
        intent.putExtra(EXTRA_RECEIVER, receiver);
        intent.putExtra(EXTRA_ADDRESS, address);
        intent.putExtra(AddressService.EXTRA_TYPE, TYPE_ADDRESS);
        context.startService(intent);
    }

    public static void fromLocation(Context context, ResultReceiver receiver, double lng, double lat) {
        toAddressService(context, receiver, lng, lat, TYPE_LOCATION);
    }

    public static void testNearby(Context context, ResultReceiver receiver) {
        fromNearby(context, receiver, 110.334387, 21.263442);
    }

    public static void fromNearby(Context context, ResultReceiver receiver, double lng, double lat) {
        toAddressService(context, receiver, lng, lat, TYPE_NEARBY);
    }

    public static void toAddressService(Context context, ResultReceiver receiver, double lng, double lat, int type) {
        Intent intent = new Intent(context, AddressService.class);
        intent.putExtra(AddressService.EXTRA_RECEIVER, receiver);
        intent.putExtra(AddressService.EXTRA_LONGITUDE, lng);
        intent.putExtra(AddressService.EXTRA_LATITUDE, lat);
        intent.putExtra(AddressService.EXTRA_TYPE, type);
        context.startService(intent);
    }


    public AddressService() {
        super("AddressService");
    }

    @Override
    protected void onHandleIntent(@Nullable Intent intent) {

        String errorMessage = "";

        mReceiver = intent.getParcelableExtra(EXTRA_RECEIVER);
        if (mReceiver == null) {
            return;
        }

        //根据文字搜索地理位置
        if (intent.hasExtra(EXTRA_ADDRESS)) {
            String address = intent.getStringExtra(EXTRA_ADDRESS);
            fetchAddress(address);
            return;
        }

        //根据经纬度搜索地理位置
        double lat = intent.getDoubleExtra(EXTRA_LATITUDE, 0);
        double lng = intent.getDoubleExtra(EXTRA_LONGITUDE, 0);
        Log.i(TAG, String.valueOf(lng));
        Log.i(TAG, String.valueOf(lat));

        int type = intent.getIntExtra(EXTRA_TYPE, TYPE_LOCATION);
        if (type == TYPE_NEARBY) {
            fetchNearby(lat, lng);
            return;
        }

        Geocoder geocoder = new Geocoder(this, Locale.getDefault());
        try {
            List<Address> addresses = geocoder.getFromLocation(lat, lng, 1);
            if (addresses == null || addresses.isEmpty()) {
                fetchAddress(lat, lng);
                return;
            }
            onGeoCoder(addresses);
        } catch (IOException ioException) {
            fetchAddress(lat, lng);
            Log.e(TAG, errorMessage, ioException);
        } catch (IllegalArgumentException illegalArgumentException) {
            failure(ERROR_GEO_INVALID);
        }
    }

    private void onGeoCoder(List<Address> addresses) {
        ArrayList<com.zadtek.sharkRider.util.gmap.Address> list = new ArrayList<>(addresses.size());
        for (Address address : addresses) {
            com.zadtek.sharkRider.util.gmap.Address a = new com.zadtek.sharkRider.util.gmap.Address();
            StringBuilder sb = new StringBuilder();
            /**省+市+区+道路*/
            sb.append(address.getAdminArea());
            sb.append(address.getLocality());
            sb.append(address.getSubLocality());
            sb.append(address.getThoroughfare());

            a.address = sb.toString();
            a.lat = address.getLatitude();
            a.lng = address.getLongitude();
            a.title = address.getAdminArea();
            list.add(a);
        }

        successful(list);
    }

    private void successful(ArrayList<com.zadtek.sharkRider.util.gmap.Address> addresses) {
        Bundle bundle = new Bundle();
        bundle.putParcelableArrayList(EXTRA_ADDRESS, addresses);
        mReceiver.send(RESULT_SUCCESS, bundle);
    }

    private void failure(String message) {
        Bundle bundle = new Bundle();
        bundle.putString(EXTRA_FAILURE, message);
        mReceiver.send(RESULT_FAILURE, bundle);
    }

    /**
     * &types=point_of_interest
     * &rankby=distance
     * https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=23.006000,72.601100&types=point_of_interest&radius=50000&sensor=false&key=AIzaSyD0XQN_CDaaas0jZtbhnhQD1hsf1Bb7DHo
     * https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=23.165912,113.424065&radius=50000&sensor=false&key=AIzaSyD0XQN_CDaaas0jZtbhnhQD1hsf1Bb7DHo
     */
    private void fetchNearby(double lat, double lng) {
        StringBuilder url = new StringBuilder();
        url.append("https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=")
                .append(lat).append(",").append(lng);
       /* url.append("&radius=500&sensor=false&key=")
                .append(getString(R.string.google_maps_key));*/
        Log.i(TAG, url.toString());
        StringRequest request = new StringRequest(url.toString(), new Response.Listener<String>() {
            @Override
            public void onResponse(String json) {
                Log.i(TAG, json);
                onFetchNearby(json);
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError volleyError) {
                failure(ERROR_GOOGLE_SERVICE_INVALID);
            }
        });

        Volley.newRequestQueue(getApplicationContext()).add(request);
    }

    /**
     * http://maps.googleapis.com/maps/api/geocode/json?address=广东省湛江市麻章&sensor=false&language=zh-CN
     */
    private void fetchAddress(String address) {

        StringBuilder url = new StringBuilder();
        url.append("http://maps.googleapis.com/maps/api/geocode/json?address=").append(address);
        url.append("&sensor=false&language=").append(Locale.getDefault().getCountry());
        fetch(url.toString());
    }

    /**
     * http://maps.googleapis.com/maps/api/geocode/json?latlng=21.263442,110.334387&sensor=false&language=zh-CN
     */
    private void fetchAddress(double lat, double lng) {
        StringBuilder url = new StringBuilder();
        url.append("http://maps.googleapis.com/maps/api/geocode/json?latlng=").append(lat).append(",").append(lng);
        url.append("&sensor=false&language=").append(Locale.getDefault().getCountry());
        fetch(url.toString());
    }

    private void fetch(String url) {
        Log.i(TAG, url.toString());
        StringRequest request = new StringRequest(url.toString(), new Response.Listener<String>() {
            @Override
            public void onResponse(String json) {
                Log.i(TAG, json);
                onFetchAddress(json);
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError volleyError) {
                failure(ERROR_GOOGLE_SERVICE_INVALID);
            }
        });

        Volley.newRequestQueue(getApplicationContext()).add(request);
    }


    private void onFetchAddress(String json) {
        try {
            JSONObject object = new JSONObject(json);
            if (!object.has("results") || object.isNull("results")) {
                failure(ERROR_DATA_INVALID);
                return;
            }

            JSONArray results = object.getJSONArray("results");
            int size = results.length();
            ArrayList<com.zadtek.sharkRider.util.gmap.Address> addresses = new ArrayList<>(size);
            for (int i = 0; i < size; i++) {
                JSONObject item = results.getJSONObject(i);
                String formatted_address = item.getString("formatted_address");
                JSONObject location = item.getJSONObject("geometry").getJSONObject("location");

                JSONArray address_components = item.getJSONArray("address_components");
                String short_name = address_components.getJSONObject(0).getString("short_name");

                com.zadtek.sharkRider.util.gmap.Address address = new com.zadtek.sharkRider.util.gmap.Address();
                address.address = formatted_address;
                address.lat = location.getDouble("lat");
                address.lng = location.getDouble("lng");
                address.title = short_name;

                addresses.add(address);
            }
            successful(addresses);
        } catch (Exception e) {
            e.printStackTrace();
            failure(ERROR_DATA_INVALID);
        }
    }

    private void onFetchNearby(String json) {
        try {
            JSONObject object = new JSONObject(json);
            String status = object.getString("status");
            if (!TextUtils.equals("OK", status)) {
                failure(ERROR_DATA_INVALID);
                return;
            }

            if (!object.has("results") || object.isNull("results")) {
                failure(ERROR_DATA_INVALID);
                return;
            }

            JSONArray results = object.getJSONArray("results");
            int size = results.length();
            ArrayList<com.zadtek.sharkRider.util.gmap.Address> addresses = new ArrayList<>(size);
            for (int i = 0; i < size; i++) {
                JSONObject item = results.getJSONObject(i);
                String formatted_address = item.getString("vicinity");
                String name = item.getString("name");
                JSONObject location = item.getJSONObject("geometry").getJSONObject("location");

                com.zadtek.sharkRider.util.gmap.Address address = new com.zadtek.sharkRider.util.gmap.Address();
                address.address = formatted_address;
                address.lat = location.getDouble("lat");
                address.lng = location.getDouble("lng");
                address.title = name;

                addresses.add(address);
            }
            successful(addresses);
        } catch (Exception e) {
            e.printStackTrace();
            failure(ERROR_DATA_INVALID);
        }
    }
}
